package cn.yunlang.zhangZhongFei.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.yunlang.zhangZhongFei.constant.CacheConstant;
import cn.yunlang.zhangZhongFei.entity.Award;
import cn.yunlang.zhangZhongFei.entity.AwardMessage;
import cn.yunlang.zhangZhongFei.entity.WinAward;
import cn.yunlang.zhangZhongFei.mapper.AwardMapper;
import cn.yunlang.zhangZhongFei.service.AwardMessageService;
import cn.yunlang.zhangZhongFei.service.AwardService;
import cn.yunlang.zhangZhongFei.service.WinAwardService;
import cn.yunlang.zhangZhongFei.util.CheckEmptyUtil;
import cn.yunlang.zhangZhongFei.util.RedisUtil;
import cn.yunlang.zhangZhongFei.vo.request.AwardVo;
import cn.yunlang.zhangZhongFei.vo.request.ChanceVo;
import cn.yunlang.zhangZhongFei.vo.response.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

/**
 * 奖品表 服务实现类
 *
 * @author ·
 * @since 2025-05-27 09:54:49
 */
@Slf4j
@Service
public class AwardServiceImpl extends ServiceImpl<AwardMapper, Award> implements AwardService {
  @Autowired private AwardMapper awardMapper;
  @Resource private RedisUtil redisUtil;
  @Resource private AwardMessageService awardMessageService;
  @Resource private WinAwardService winAwardService;

  @Override
  public Award selectId(Long awardId) {
    if (awardId == null) {
      throw new IllegalArgumentException("奖品ID不能为空");
    }
    Award award = awardMapper.selectById(awardId);
    if (award == null) {
      throw new RuntimeException("未找到对应的奖品信息");
    }
    return award;
  }

  @Override
  public R<IPage<Award>> pageAwards(Integer pageNo, Integer pageSize, String awardName) {
    if (pageNo == null || pageSize == null) {
      return R.error(400, "分页参数不能为空");
    }
    if (pageNo < 1) {
      pageNo = 1;
    }
    if (pageSize < 1) {
      pageSize = 10;
    }
    LambdaQueryWrapper<Award> wrapper = new LambdaQueryWrapper<>();
    wrapper.like(StringUtils.hasText(awardName), Award::getAwardName, awardName);
    wrapper.orderByDesc(Award::getCreateTime);
    Page<Award> page = new Page<>(pageNo, pageSize);
    IPage<Award> result = this.page(page, wrapper);
    return R.success(result);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean addAward(Award award) {
    // 参数校验
    if (award == null) {
      throw new IllegalArgumentException("奖品信息不能为空");
    }
    if (CheckEmptyUtil.isEmpty(award.getAwardName())) {
      throw new IllegalArgumentException("奖品名称不能为空");
    }
    if (CheckEmptyUtil.isEmpty(award.getAwardPic())) {
      throw new IllegalArgumentException("奖品图片不能为空");
    }
    if (award.getAwardCount() == null || award.getAwardCount() < 0) {
      throw new IllegalArgumentException("奖品数量不能为空且必须大于等于0");
    }
    if (award.getStartTime() == null) {
      throw new IllegalArgumentException("开始时间不能为空");
    }
    if (award.getMinutes() == null || award.getMinutes() <= 0) {
      throw new IllegalArgumentException("活动时长必须大于0");
    }

    // 检查奖品名称是否重复
    LambdaQueryWrapper<Award> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(Award::getAwardName, award.getAwardName());
    if (this.count(queryWrapper) > 0) {
      throw new RuntimeException("奖品名称已存在");
    }

    // 设置结束时间
    DateTime endTime = DateUtil.offsetMinute(award.getStartTime(), award.getMinutes());
    award.setEndTime(endTime);

    // 保存奖品信息
    boolean save = this.save(award);
    if (save) {
      // 缓存奖品信息
      String awardId = award.getId().toString();
      redisUtil.set(CacheConstant.AWARD + awardId + ":name", award.getAwardName());
      redisUtil.set(CacheConstant.AWARD + awardId + ":pic", award.getAwardPic());
      redisUtil.set(CacheConstant.AWARD + awardId + ":price", award.getAwardPrice().toString());
      redisUtil.set(CacheConstant.AWARD + awardId + ":count", award.getAwardCount().toString());
    }
    return save;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean updateAward(Award award) {
    // 参数校验
    if (award == null || award.getId() == null) {
      throw new IllegalArgumentException("奖品信息或ID不能为空");
    }

    // 检查奖品是否存在
    Award existingAward = this.getById(award.getId());
    if (existingAward == null) {
      throw new RuntimeException("未找到对应的奖品信息");
    }

    // 如果修改了奖品名称，检查是否与其他奖品重复
    if (!Objects.equals(existingAward.getAwardName(), award.getAwardName())) {
      LambdaQueryWrapper<Award> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper.eq(Award::getAwardName, award.getAwardName()).ne(Award::getId, award.getId());
      if (this.count(queryWrapper) > 0) {
        throw new RuntimeException("奖品名称已存在");
      }
    }

    // 更新结束时间
    if (award.getStartTime() != null && award.getMinutes() != null) {
      DateTime endTime = DateUtil.offsetMinute(award.getStartTime(), award.getMinutes());
      award.setEndTime(endTime);
    }

    // 更新奖品信息
    boolean update = this.updateById(award);
    if (update) {
      // 更新缓存
      String awardId = award.getId().toString();
      redisUtil.set(CacheConstant.AWARD + awardId + ":name", award.getAwardName());
      redisUtil.set(CacheConstant.AWARD + awardId + ":pic", award.getAwardPic());
      redisUtil.set(CacheConstant.AWARD + awardId + ":price", award.getAwardPrice().toString());
      redisUtil.set(CacheConstant.AWARD + awardId + ":count", award.getAwardCount().toString());
    }
    return update;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean deleteAward(Long awardId) {
    if (awardId == null) {
      throw new IllegalArgumentException("奖品ID不能为空");
    }

    // 检查奖品是否存在
    Award award = this.getById(awardId);
    if (award == null) {
      throw new RuntimeException("未找到对应的奖品信息");
    }

    // 删除奖品信息
    boolean remove = this.removeById(awardId);
    if (remove) {
      // 删除缓存
      String keyBegin = CacheConstant.AWARD + awardId;
      redisUtil.del(keyBegin + ":name");
      redisUtil.del(keyBegin + ":pic");
      redisUtil.del(keyBegin + ":price");
      redisUtil.del(keyBegin + ":count");
    }
    return remove;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public String getChance(ChanceVo chanceVo) {
    if (chanceVo == null) {
      throw new IllegalArgumentException("抽奖机会信息不能为空");
    }
    if (chanceVo.getAwardId() == null) {
      throw new IllegalArgumentException("奖品ID不能为空");
    }
    if (CheckEmptyUtil.isEmpty(chanceVo.getText())) {
      throw new IllegalArgumentException("口令不能为空");
    }
    if (CheckEmptyUtil.isEmpty(chanceVo.getUserId())) {
      throw new IllegalArgumentException("用户ID不能为空");
    }

    // 保存抽奖消息
    AwardMessage awardMessage = new AwardMessage();
    BeanUtils.copyProperties(chanceVo, awardMessage);
    awardMessageService.save(awardMessage);

    // 验证口令
    Award award = this.selectId(chanceVo.getAwardId());
    if (!CheckEmptyUtil.isEmpty(award)
        && Objects.equals(chanceVo.getText(), award.getAwardText())) {
      redisUtil.set(
          CacheConstant.AWARD + award.getId() + ":joinUser:" + chanceVo.getUserId(),
          CacheConstant.CAN);
      return "口令匹配,可以参加抽奖！";
    }
    return "口令不匹配";
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public String joinAward(AwardVo awardVo) {
    if (awardVo == null) {
      throw new IllegalArgumentException("抽奖信息不能为空");
    }
    if (awardVo.getAwardId() == null) {
      throw new IllegalArgumentException("奖品ID不能为空");
    }
    if (CheckEmptyUtil.isEmpty(awardVo.getUserId())) {
      throw new IllegalArgumentException("用户ID不能为空");
    }

    // 查询活动信息
    Award award = this.selectId(awardVo.getAwardId());
    Date now = new Date();

    // 检查活动是否已结束
    if (now.after(award.getEndTime()) && !"2".equals(award.getState())) {
      // 活动刚结束，更新状态为已结束
      award.setState("2");
      this.updateById(award);

      // 获取所有参与用户
      String keyBegin = CacheConstant.AWARD + award.getId();
      Set<String> joinUsers = redisUtil.sMembers(keyBegin + ":joinUsers");
      if (joinUsers != null && !joinUsers.isEmpty()) {
        // 获取奖品数量
        String count = redisUtil.get(keyBegin + ":count");
        int awardCount = Integer.parseInt(count);
        int joinCount = joinUsers.size();

        // 随机抽取中奖用户
        List<String> userIds = new ArrayList<>(joinUsers);
        Collections.shuffle(userIds);

        // 确定中奖人数
        int winCount = Math.min(awardCount, joinCount);

        // 记录中奖信息
        for (int i = 0; i < winCount; i++) {
          String userId = userIds.get(i);
          WinAward winAward = new WinAward();
          BeanUtils.copyProperties(award, winAward, "id", "createTime");
          winAward.setUserId(Long.valueOf(userId));
          winAward.setAwardId(award.getId());
          winAwardService.save(winAward);
          log.info("用户{}在{}人参与中抽中奖品{}", userId, joinCount, award.getId());
        }

        // 清理缓存
        redisUtil.delAll(keyBegin);
        log.info("奖品{}抽奖完成，共{}人参与，{}人中奖", award.getId(), joinCount, winCount);
      }
    }

    // 检查活动状态
    if ("2".equals(award.getState())) {
      return "活动已结束";
    }
    if (now.before(award.getStartTime())) {
      return "活动未开始";
    }
    if (!"1".equals(award.getState())) {
      return "活动状态异常";
    }

    String keyBegin = CacheConstant.AWARD + awardVo.getAwardId();
    String lockKey = keyBegin + ":lock";
    boolean lock = redisUtil.set(lockKey, "lock", 10000);
    if (!lock) {
      return "当前请求人数较多，请稍后重试";
    }

    try {
      // 检查抽奖机会
      String s = redisUtil.get(keyBegin + ":joinUser:" + awardVo.getUserId());
      if (CheckEmptyUtil.isEmpty(s)) {
        return "没有抽奖机会，请先发送口令";
      }
      if (s.equals(CacheConstant.CANNOT)) {
        return "已经参与过抽奖";
      }

      // 标记已参与
      redisUtil.set(keyBegin + ":joinUser:" + awardVo.getUserId(), CacheConstant.CANNOT);
      
      // 记录参与用户
      redisUtil.sAdd(keyBegin + ":joinUsers", String.valueOf(awardVo.getUserId()));
      redisUtil.expire(
          keyBegin + ":joinUsers", award.getEndTime().getTime() - System.currentTimeMillis());

      return "参与成功";
    } finally {
      redisUtil.del(lockKey);
    }
  }

  @Override
  public WinAward checkWinStatus(AwardVo awardVo) {
    if (awardVo == null) {
      throw new IllegalArgumentException("抽奖信息不能为空");
    }
    if (awardVo.getAwardId() == null) {
      throw new IllegalArgumentException("奖品ID不能为空");
    }
    if (CheckEmptyUtil.isEmpty(awardVo.getUserId())) {
      throw new IllegalArgumentException("用户ID不能为空");
    }

    return winAwardService.getOne(
        new LambdaQueryWrapper<WinAward>()
            .eq(WinAward::getAwardId, awardVo.getAwardId())
            .eq(WinAward::getUserId, awardVo.getUserId())
            .last("limit 1"));
  }
}
